abiosoft / ishell Goto Github PK
View Code? Open in Web Editor NEWLibrary for creating interactive cli applications.
License: MIT License
Library for creating interactive cli applications.
License: MIT License
The README says you are advised to upgrade to the the current master instead of v1. However, there's no v2 tag anywhere. dep
installs the latest release by default, so it will still install v1.
Perhaps there is a better way to do this but it's currently escaping me so any advice is appreciated.
I'm writing a custom interrupt handler but I'd like to make use of interruptCount similar to the way the default handler function works. But I don't believe I have access to that interruptCount variable to check or increment.
Perhaps making that variable public or giving access to it in some other way?
Alternatively, giving a hook where the count can be reset would work as well.
Again, if I'm missing something then I'd appreciate a point in the right direction.
Thanks!
Hi,
given that I have a chain of Cmds (update, user, set, name) and "john" being an argument:
>>> update user set name john
It would be nice to have the invocation of this string as a subsequent invocation of all cmds in the chain. resulting in:
update.Func() -> user.Func() -> set.Func() -> name.Func() -> (c.Args[0] == john)
rather than only the function of name
right now I could parse c.RawArgs when name.Func() is called and call each cmds by myself. but it would be nice to have it built in into ishell.
hi,
I am thinking of a pipe operator in ishell. so you could pipe through another function:
>>> print "hello" | func1
stdout (or return of the print function) is piped into func1 as stdin (or input arguments).
is this possible or any plans to implement this?
As the title suggested. We are using your library to build some application, and the symbols you have in Multiple Choice and Checklist show up greatly on terminal clients that support proper UTF-8 fonts. Unfortunately, this is not true across the organization and we had some complains about characters not show up correctly.
Can we make those characters customizable so that I can change them to something more ASCI friendly?
Best regards,
Hi,
I could not find this function when I scanned the code: is it possible to have a kind of interactive startup, where, e.g., the user is asked to provide some information right after starting the application when some condition is met? For example, if a configuration parameter (path) is missing, then the user is asked right after startup to input this information, without the need to enter a command.
Example:
$user: go run myapp.go
This is myApp
Seems like this is the first start of the app. Please enter the directory to save the data:
>>>
The attached program creates two commands; the first, "foo", uses ishell.Context.Println() to print "foo', and the second, "bar" uses ishell.Context.Printf() to print "bar". If I build it and run it (on OSX, FWIW), giving it the command "foo", gives me one "foo" printed, but multiple "bar"s are printed for the "bar" command. (Note that the output looks like I entered "bar" multiple times, but I actually only entered it once.)
go build . && ./bug
>>> foo
foo
>>> bar
bar
>>> bar
>>> bar
^D
EOF
Looking at actions.go, I notice that Println() only sends output to s.writer, but that Print() and Printf() send output to both that and s.reader.buf. I haven't dug further to understand why this is.
The autocompletion for command aliases does not work.
file: 'file:///c%3A/Users/wiecbuk/go/src/stash.dts.fm.rbsgrp.net/ep/edt_command_client.git/spike.go'
severity: 'Error'
message: 'unknown field 'Aliases' in struct literal of type ishell.Cmd'
at: '44,3'
source: ''
file: 'file:///c%3A/Users/wiecbuk/go/src/stash.dts.fm.rbsgrp.net/ep/edt_command_client.git/spike.go'
severity: 'Error'
message: 'c.MultiChoice undefined (type *ishell.Context has no field or method MultiChoice)'
at: '72,4'
source: ''
file: 'file:///c%3A/Users/wiecbuk/go/src/stash.dts.fm.rbsgrp.net/ep/edt_command_client.git/spike.go'
severity: 'Error'
message: 'c.Checklist undefined (type *ishell.Context has no field or method Checklist)'
at: '92,4'
source: ''
file: 'file:///c%3A/Users/wiecbuk/go/src/stash.dts.fm.rbsgrp.net/ep/edt_command_client.git/spike.go'
severity: 'Error'
message: 'shell.Process undefined (type *ishell.Shell has no field or method Process)'
at: '193,3'
source: ''
file: 'file:///c%3A/Users/wiecbuk/go/src/stash.dts.fm.rbsgrp.net/ep/edt_command_client.git/spike.go'
severity: 'Error'
message: 'shell.Run undefined (type *ishell.Shell has no field or method Run)'
at: '196,3'
source: ''
file: 'file:///c%3A/Users/wiecbuk/go/src/stash.dts.fm.rbsgrp.net/ep/edt_command_client.git/spike.go'
severity: 'Error'
message: 'shell.Close undefined (type *ishell.Shell has no field or method Close)'
at: '198,3'
source: ''
SHIFT+TAB for moving backwards in word suggestions (completer) would be nice.
I propose https://github.com/fatih/color
When I press ctrl-z while my cmd app is in focus, all text in current line disappears including '>>>', and the window doesn't respond to key presses.
I want to expose some values to all my shell commands, without resorting to global values, so the context values map seems an obvious way to do so.
However, right now, I can only access these values through a Context object, while executing a command, not from the outside. Duplicating Get/Set/Delete/Keys from context onto Shell is probably sufficient for this? Perhaps renaming to GetContextValue() etc to make it more explicit?
hi,
I have also been working on a package to implement interactive shells, like python's cmd
module:
https://github.com/go-hep/pawgo/blob/master/cmd.go
(I haven't extracted it yet from this pawgo command...)
I'd recommand the github.com/peterh/liner
package for completion, history and terminal handling.
fmt.Printf
doesn't work when there is no new-line character at the end of the string.
// This works fine
shell.AddCmd(&ishell.Cmd{
Name: "hello",
Func: func(c *ishell.Context) {
fmt.Printf("Hello\n")
},
})
// This does not
shell.AddCmd(&ishell.Cmd{
Name: "hello",
Func: func(c *ishell.Context) {
fmt.Printf("Hello")
},
})
Hi all,
first of all great piece of software. really like it.
I would like to know if there is an option equivalent to ClearScreen() but one which only clears the actual line instead of the whole screen.
so for example:
>>> something written on this line
and when I hit CTRL + C (which I can catch with Interrupt()) I want the line to be empty on the same line:
>>>
without moving into a new prompt line.
is this possible?
Any thoughts on what it would take to integrate ishell with termbox-go? I would love to embed ishell into a multi-pane terminal app framework like https://github.com/jroimartin/gocui
Thanks!
It seems shlex
has quite weird behaviour for escaped characters.
If you enter:
>>> command "a\tb"
The argument you get will be atb
. Typing an actual literal tab character is ignored by the shell, so it's also not possible to enter a tab that way.
I don't see a very easy way to fix this, especially since shlex
is not maintained anymore. Would you be okay with a PR that removes the dependency on shlex
and uses strconv.Unquote()
to handle escaping and quoting?
I have 2 ReadLine() questions and when I hit Ctrl+C on any of them, the program is not exiting as expected, but proceeding to the next question.
var name, displayName string
sh := ishell.New()
sh.AddCmd(&ishell.Cmd{
Name: "default",
Func: func(c *ishell.Context) {
c.Printf("Name: ")
name = c.ReadLine()
c.Printf("Display name (optional): ")
displayName = c.ReadLine()
}})
sh.Process("default")
fmt.Println("Answers:", name, displayName)
Hit Ctrl+c on the first question, falls back to second question:
Name: ^C
Display name (optional):
hit Ctrl+C on second question, it proceeded on running the rest of the program:
Name: ^C
Display name (optional): ^C
Answers:
it should be quitting the program on first Ctrl+C.
Seeing how the completer and readline integration works, I think suggestions containing spaces should be put in quotation marks upon completion. Also, prefixes beginning with a quotation mark should be handled correctly, e.g.: "foo
+ TAB should complete both foobar
as well as "foo bar"
.
No content is displayed when running a multiple choice command a macOS terminal.
I tried without success to use some library for spinners ( github.com/briandowns/spinner ) but it seems that the shell is taking over the display.
This is a feature request: compatibility with some spinners and progress bar libraries, or core integration of the feature.
I would use the spinner for waiting until timeouts, and the progress bar to display some incoming time info about an operation in progress.
Thanks for your library anyway
In the /examples folder have more practical examples in separate files, for example, in the smod project:
https://github.com/enddo/smod
SMOD > show modules
Modules Description
modbus/dos/arp DOS with Arp Poisoning
modbus/dos/galilRIO DOS Galil RIO-47100
modbus/dos/writeAllCoils DOS With Write All Coils
modbus/dos/writeAllRegister DOS With Write All Register Function
modbus/dos/writeSingleCoils DOS With Write Single Coil Function
modbus/dos/writeSingleRegister DOS Write Single Register Function
modbus/function/fuzzing Fuzzing Modbus Functions
modbus/function/readCoils Fuzzing Read Coils Function
modbus/function/readCoilsException Fuzzing Read Coils Exception Function
modbus/function/readDiscreteInput Fuzzing Read Discrete Inputs Function
modbus/function/readDiscreteInputException Fuzzing Read Discrete Inputs Exception Function
modbus/function/readExceptionStatus Fuzzing Read Exception Status Function
modbus/function/readHoldingRegister Fuzzing Read Holding Registers Function
modbus/function/readHoldingRegisterException Fuzzing Read Holding Registers Exception Function
modbus/function/readInputRegister Fuzzing Read Input Registers Function
modbus/function/readInputRegisterException Fuzzing Read Input Registers Exception Function
modbus/function/writeSingleCoils Fuzzing Write Single Coil Function
modbus/function/writeSingleRegister Fuzzing Write Single Register Function
modbus/scanner/arpWatcher ARP Watcher
modbus/scanner/discover Check Modbus Protocols
modbus/scanner/getfunc Enumeration Function on Modbus
modbus/scanner/uid Brute Force UID
modbus/sniff/arp Arp Poisoning
Structure in linux filesystem:
/scada/tools/smod/Application# tree
.
└── modules
└── modbus
├── dos
│ ├── arp.py
│ ├── arp.pyc
│ ├── galilRIO.py
│ ├── galilRIO.pyc
│ ├── writeAllCoils.py
│ ├── writeAllCoils.pyc
│ ├── writeAllRegister.py
│ ├── writeAllRegister.pyc
│ ├── writeSingleCoils.py
│ ├── writeSingleCoils.pyc
│ ├── writeSingleRegister.py
│ └── writeSingleRegister.pyc
├── function
│ ├── fuzzing.py
│ ├── fuzzing.pyc
│ ├── readCoilsException.py
│ ├── readCoilsException.pyc
│ ├── readCoils.py
│ ├── readCoils.pyc
│ ├── readDiscreteInputException.py
│ ├── readDiscreteInputException.pyc
│ ├── readDiscreteInput.py
│ ├── readDiscreteInput.pyc
│ ├── readExceptionStatus.py
│ ├── readExceptionStatus.pyc
│ ├── readHoldingRegisterException.py
│ ├── readHoldingRegisterException.pyc
│ ├── readHoldingRegister.py
│ ├── readHoldingRegister.pyc
│ ├── readInputRegisterException.py
│ ├── readInputRegisterException.pyc
│ ├── readInputRegister.py
│ ├── readInputRegister.pyc
│ ├── writeSingleCoils.py
│ ├── writeSingleCoils.pyc
│ ├── writeSingleRegister.py
│ └── writeSingleRegister.pyc
├── scanner
│ ├── arpWatcher.py
│ ├── arpWatcher.pyc
│ ├── discover.py
│ ├── discover.pyc
│ ├── getfunc.py
│ ├── getfunc.pyc
│ ├── uid.py
│ └── uid.pyc
└── sniff
├── arp.py
└── arp.pyc
6 directories, 46 files
I would like to create a form of file structure in the filesystem of my project and that it would be called inside the source code in golang in ishell. An example in the / examples folder would be cool, even because the current example would already be the next step to this.
The more practical examples you have, the more developers will certainly use your project, which by the way is a great project.
Hello guys,
tryed the main.go in the examples folder, seems like there is a problem with the readPassword() on go version go1.9.1 darwin/amd64 (mac)
`panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x1206f61]
goroutine 1 [running]:
github.com/chzyer/readline.(*RuneBuffer).output(0xc42008c8c0, 0x0, 0xc420051838, 0x120817c)
/Users/xxxx/Go/src/github.com/chzyer/readline/runebuf.go:494 +0xd1
github.com/chzyer/readline.(*RuneBuffer).print(0xc42008c8c0)
/Users/xxxx/Go/src/github.com/chzyer/readline/runebuf.go:475 +0x2b
github.com/chzyer/readline.(*RuneBuffer).Refresh(0xc42008c8c0, 0x0)
/Users/xxxx/Go/src/github.com/chzyer/readline/runebuf.go:465 +0xb2
github.com/chzyer/readline.(*Operation).Runes(0xc4200fe000, 0x0, 0x0, 0x0, 0x0, 0x0)
/Users/xxxx/Go/src/github.com/chzyer/readline/operation.go:388 +0xf9
github.com/chzyer/readline.(*Operation).Slice(0xc4200fe000, 0x12c1710, 0xc420010b50, 0x0, 0x107be01, 0xc420166d80)
/Users/xxxx/Go/src/github.com/chzyer/readline/operation.go:429 +0x2f
github.com/chzyer/readline.(*Operation).PasswordWithConfig(0xc4200fe000, 0xc420166d80, 0x0, 0x0, 0x0, 0x0, 0x0)
/Users/xxxx/Go/src/github.com/chzyer/readline/operation.go:417 +0xb5
github.com/chzyer/readline.(*Operation).PasswordEx(0xc4200fe000, 0xc420160166, 0xa, 0x0, 0x0, 0x0, 0xc420051b48, 0xc42011c000, 0x16006c8, 0x0)
/Users/xxxx/Go/src/github.com/chzyer/readline/operation.go:405 +0x165
github.com/chzyer/readline.(*Operation).Password(0xc4200fe000, 0xc420160166, 0xa, 0x1045db9, 0xc420160166, 0xc42013e028, 0xa, 0xc420160166)
/Users/xxxx/Go/src/github.com/chzyer/readline/operation.go:421 +0x55
github.com/chzyer/readline.(*Instance).ReadPassword(0xc42012c000, 0xc420160166, 0xa, 0x40, 0xc420160166, 0xa, 0x20, 0xa)
/Users/xxxx/Go/src/github.com/chzyer/readline/readline.go:232 +0x43
github.com/abiosoft/ishell.(*shellReader).readPasswordErr(0xc420134060, 0x1210932, 0x13eb220, 0xc42000e018, 0xc42016a160)
/Users/xxxx/Go/src/github.com/abiosoft/ishell/reader.go:49 +0xd5
github.com/abiosoft/ishell.(*shellReader).readPassword(0xc420134060, 0x0, 0x0)
/Users/xxxx/Go/src/github.com/abiosoft/ishell/reader.go:54 +0x2b
github.com/abiosoft/ishell.(*shellActionsImpl).ReadPassword(0xc420140000, 0xc42016a160, 0x1)
/Users/xxxx/Go/src/github.com/abiosoft/ishell/actions.go:81 +0x32
main.main.func1(0xc42018a000)
/Volumes/Secondary/Boulot/Experiments/go/genious/gcreport/gcreport.go:63 +0x24f
github.com/abiosoft/ishell.(*Shell).handleCommand(0xc420132000, 0xc42016a0a0, 0x1, 0x1, 0x1213c96, 0xc420051de8, 0xc420051dd8)
/Users/xxxx/Go/src/github.com/abiosoft/ishell/ishell.go:248 +0x2fc
github.com/abiosoft/ishell.handleInput(0xc420132000, 0xc42016a0a0, 0x1, 0x1, 0xc420132000, 0xc420156060)
/Users/xxxx/Go/src/github.com/abiosoft/ishell/ishell.go:202 +0x4d
github.com/abiosoft/ishell.(*Shell).run(0xc420132000)
/Users/xxxx/Go/src/github.com/abiosoft/ishell/ishell.go:181 +0x245
github.com/abiosoft/ishell.(*Shell).Run(0xc420132000)
/Users/xxxx/Go/src/github.com/abiosoft/ishell/ishell.go:97 +0x39
main.main()
/Volumes/Secondary/Boulot/Experiments/go/genious/gcreport/gcreport.go:77 +0x1c0
exit status 2`
Hello guys,
I think it would be great to call (jump to) a command from another command.
Here is an usage example :
The idea is calling the first command from the second one when the user is done reading the details about the log entry he selected.. So it basically returns him to the list of logs
Are there alternatives to this package?
I'd like to compare most of them allow to build CLI apps but I couldn't find a way to build interactive shells like this app.
I am trying to print some output from a channel to the shell. When receiving from a goroutine it prints without a newline and does not give the prompt back. Example:
package main
import (
"time"
"github.com/abiosoft/ishell"
)
func feed(c chan string) {
for i := 0; i<3; i++ {
c <- "Feedback"
time.Sleep(time.Second)
}
}
func main(){
shell := ishell.New()
c := make(chan string)
// listen
go func() {
for msg := range(c) {
shell.Println(msg)
}
}()
// this does output correctly
//feed(c)
// this does not
go feed(c)
shell.Start()
}
go feed(c)
outputs:
>>> Feedback
Feedback
Feedback
To get the prompt back you have to type a letter
feed(c)
outputs correctly:
Feedback
Feedback
Feedback
>>>
Similar to #35, if the term.height is a lot less than list of options, using Up/Arrow down keys do not update screen to always show the ❯
cursor. Inquisitor.js can be a good example of how this can be performed correctly.
I can still move the cursor to point to another option, but I can't see the item I am pointing at once it's off-screen.
Any thoughts on having argument validation and/or help strings per command?
I'd like to have some kind of validation built in where I can specify that a command takes in specific args and have ishell be able to process the arguments and report any errors.
How to hide the input password while viewing the process?
thank u
Hey Abiola,
first: awesome library! Really-really enjoying it. The amount of functionality I get from just including it is staggering. Autocomplete, shell history, password masking, process bars, multiline input, paged output... Wow. Wow. Wow. So useful. Especially in devops context. Thank you for this package!
What I was thinking: how hard would it be to also allow non-interactive use? Just parsing args, executing that one single command and then exit? It would be very useful in scripted environments, like CI and such.
What are your thoughts on this?
Best,
Roman
This one is from Inquirer.js too:
Basically Inquirer.js can ask questions without clearing the screen (and printing the question to x=0 y=0) ishell currently clears the screen when called like ishell.New().MultiChoice(...)
(P.S. also in the long-list.js
example above, if the list is longer than N items, it allows limiting the scroll area to N items, while still allowing user to scroll. but that's a separate topic.)
Currently all items in MultiChoice/Checklist are selectable.
If there was a way to specify unselectable items, those could be used as section headers to separate a long list of items. While cycling through options, the cursor wouldn't land on these items, it would just move onto the next item.
Add possibility to exist current command (c.Stop) without exiting the whole shell(current behaviour).
In v1 you were able to do something like this:
shell := ishell.New()
myObj := somelib.New(arg arg arg)
shell.Register("blah", blahfunc(shell, myObj))
Then blahfunc could do all sorts of things with myObj.
Am I missing how you can do this with the v2 API?
Looking at readline, it likes like the code for Windows for the call to ClearScreen only returns 1 arg rather than 2 for Unix, causing ishell to not compile on windows because of:
https://github.com/abiosoft/ishell/blob/master/actions.go#L167
Readline Windows:
https://github.com/chzyer/readline/blob/283f5429f7723ac628cb68a44a11097c11a7a9c1/utils_windows.go#L31
Unix:
https://github.com/chzyer/readline/blob/8a1389155f133761e8e73b585f47ed27a78b74d5/utils_unix.go#L48
Having a subcommand example would be helpful.
Add support for timeout when reading line.
When someone has a long list of multi-choice questions it would be great to use PageUp/Down instead of just holding on the up/down arrow keys.
Hello,
As I am using ishell in a mix environment where I need to process shell commands as well as non shell commands that need to be sent elsewhere, I would like to discuss the feasibility to add a way to access the unprocessed set of strings (RawArgs) as opposed to the shell processed ones (removal of quotes and escaped characters handling). This would be especially useful when dealing with NotFound commands in which case you could just delegate the parsing to another handler.
What do you think?
Sorry about opening bunch of issues, just trying to gather my thoughts around what a Inquirer.js clone in Go would look like.
Currently, to read input from the user without initializing a shell session, the code looks like this:
sh := ishell.New()
sh.SetPrompt("First name :")
firstName := sh.Readline()
sh.SetPrompt("Last name :")
lastName := sh.Readline()
A more preferable way to work with the library would be like this:
...
firstName := sh.Readline("First name")
lastName := sh.Readline("Last name")
hi,
it would be a benefit to have:
// Context is an ishell context. It embeds ishell.Actions.
type Context struct {
values map[string]interface{}
values
exposed so one can iterate through the keys and values.
because right now when passing contexts from method to method with keys set by c.Set() the target method needs to know which key was meant so it can operate on it.
func NewWithConfig(conf *readline.Config) *Shell {
rl, err := readline.NewEx(conf)
if err != nil {
log.Println("Shell or operating system not supported.")
log.Fatal(err)
}
shell := &Shell{
rootCmd: &Cmd{},
reader: &shellReader{
scanner: rl,
prompt: defaultPrompt,
multiPrompt: defaultMultiPrompt,
showPrompt: true,
buf: &bytes.Buffer{},
completer: readline.NewPrefixCompleter(),
},
writer: conf.Stdout,
haltChan: make(chan struct{}),
autoHelp: true,
}
shell.Actions = &shellActionsImpl{Shell: shell}
shell.progressBar = newProgressBar(shell)
addDefaultFuncs(shell)
return shell
}
still use defaultPrompt not conf.Prompt
Have you thought about how you want command history to work? If you have some ideas on architecture for this, I'd love to help out.
Hello,
thanks for a great SW.
As a feature request I propose possibility to customize prompt.
Hello!
Thank you for your awesome library! I'm using it for CLI management.
I recently discovered that ishell fails when I enter some non-latin letters, for example "привет" accidentally.
And ishell stopping immediately:
root@cli> привет
Error: Unknown rune: 1087
<application stopped>
Could you add graceful processing for this case and just return error "incorrect rune" to CLL shell without stopping ishell application?
Thank you for your attention!
Firstly, if the list of options
to Checklist()
are greater than the row count of the terminal, the end of list is shown, even though the cursor is at the beginning
List of options: https://gist.github.com/ahmetb/f73482d3f11c0b5cdc4af1daf3cdbefd
You can see that this is the end of my options
.
If I hit UpArrow key to go back to the end of list, it successfully does:
Secondly, if the term.height is a lot less than list of options, using Up/Arrow down keys do not update screen to always show the ❯ cursor. Inquisitor.js can be a good example of how this can be performed correctly.
I can still move the cursor to point to another option, but I can't see the item I am pointing at once it's off-screen.
Can ishell allow users to hook into the PrefixCompleterInterface when we Register commands? I'd like to be able to provide autocompletion given a command currently in the read line.
For example:
$ login --
--timeout --user --password
Furthermore, the autocompletion should be dynamic (which is probably possible via readline.PcItemDynamic):
$ ls /
bin tmp sbin etc
Using master. When using Windows the multiplechoice throws an exception.
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.")
}
},
This code will reproduce the problem
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.