-
Notifications
You must be signed in to change notification settings - Fork 6
Menus
One of the key differences between this application library and most others is the ability to easily declare different "menus", in which commands (and some other things) are segregated. An example often seen out there in the security field, is programs consisting of commands ran on a server (the server menu), and commands ran on a remote host. The list of things that are specific to a menu grossly includes:
- Command sets (structured by groups)
- Prompt strings and their lower-level settings
By default, when a new console is instantiated, a menu named "" is created, and many methods
such as console.Add()
, console.AddCommand()
will attach commands and stuff to this default menu.
You need to know of this menu thing, because even if you don't intend to use them, some functions
available in them are not accessible via the console type itself. But there is a good news...
To grab the current menu:
mainMenu := console.CurrentMenu()
In our case the base ""
menu is the current one by default, so you can grab
it like this, and then manipulate it. It should be better for consistency.
In our tutorials we will use 2 menus: a Server
and a Remote
, which might be a scenario for a SSH client.
If you need several menus, create them like this:
// serverMenu will be the default one, when starting.
serverMenu := console.NewMenu("Server")
// remoteMenu will be used later
remoteMenu := console.NewMenu("Remote")
To make the server menu as the current one (remember the ""
menu is still the current):
console.SwitchMenu("Server")
Below is the usual example of how you want to use these functions in commands. Don't really
care about the struct itself, look at the Execute()
function, and how we can introspect
on the console, and change its state on the fly. We will get back to this on several occasions.
You probably won't need this command right now, just keep that somewhere and you'll come back
after the configuration, default commands, and knowing how to declare commands on your own.
// connectHost - A command that might be used to connect to a remote host, via SSH or something.
type connectHost struct {
Args struct {
URL string `description:"SSH URL of the host we want to connect to" required:"yes"`
} `positional-args:"yes" required:"yes"`
}
// Execute - The function that will be executed when the command is invoked
func (ch *connectHost) Execute(args []string) (err error) {
// At the beginning, we are in our main context (the default one)
// where we have a bunch of server commands.
current := console.CurrentMenu() // Name: "Server"
// Here we connect over to our host with our application code, etc.
// Maybe this might give you state to use later for prompts, etc.
err = mysshlib.Connect(ch.Args.URL)
if err != nil {
// In case of failure we don't switch menus.
fmt.Println(err)
return
}
// Now we switch menus. At the next readline loop, the prompt, command set,
// etc. will be those of the new menu, you don't have to deal with any of this.
console.SwitchMenu("Remote")
return
}
The following is an example switching between menus with a function as simple as the one above. Notice the changes in prompt strings and the command sets:
Note that in this example, one history sources is bound to 2 different keys for different menus, that is why you see twice the same history, along with 2 others.