| Term::ShellUI(3pm) | User Contributed Perl Documentation | Term::ShellUI(3pm) |
Term::ShellUI - A fully-featured shell-like command line environment
use Term::ShellUI;
my $term = new Term::ShellUI(
commands => {
"cd" => {
desc => "Change to directory DIR",
maxargs => 1, args => sub { shift->complete_onlydirs(@_); },
proc => sub { chdir($_[0] || $ENV{HOME} || $ENV{LOGDIR}); },
},
"chdir" => { alias => 'cd' },
"pwd" => {
desc => "Print the current working directory",
maxargs => 0, proc => sub { system('pwd'); },
},
"quit" => {
desc => "Quit this program", maxargs => 0,
method => sub { shift->exit_requested(1); },
}},
history_file => '~/.shellui-synopsis-history',
);
print 'Using '.$term->{term}->ReadLine."\n";
$term->run();
Term::ShellUI uses the history and autocompletion features of Term::ReadLine to present a sophisticated command-line interface to the user. It tries to make every feature that one would expect to see in a fully interactive shell trivial to implement. You simply declare your command set and let ShellUI take care of the heavy lifting.
This module was previously called Term::GDBUI.
A command set is the data structure that describes your application's entire user interface. It's easiest to illustrate with a working example. We shall implement the following 6 "COMMAND"s:
The 'alias' directive used to be called 'syn' (for synonym). Either term works.
This code is fairly comprehensive because it attempts to demonstrate most of Term::ShellUI's many features. You can find a working version of this exact code titled "synopsis" in the examples directory. For a more real-world example, see the fileman-example in the same directory.
sub get_commands
{
return {
"help" => {
desc => "Print helpful information",
args => sub { shift->help_args(undef, @_); },
method => sub { shift->help_call(undef, @_); }
},
"h" => { alias => "help", exclude_from_completion=>1},
"exists" => {
desc => "List whether files exist",
args => sub { shift->complete_files(@_); },
proc => sub {
print "exists: " .
join(", ", map {-e($_) ? "<$_>":$_} @_) .
"\n";
},
doc => <<EOL,
Comprehensive documentation for our ls command.
If a file exists, it is printed in <angle brackets>.
The help can\nspan\nmany\nlines
EOL
},
"show" => {
desc => "An example of using subcommands",
cmds => {
"warranty" => { proc => "You have no warranty!\n" },
"args" => {
minargs => 2, maxargs => 2,
args => [ sub {qw(create delete)},
\&Term::ShellUI::complete_files ],
desc => "Demonstrate method calling",
method => sub {
my $self = shift;
my $parms = shift;
print $self->get_cname($parms->{cname}) .
": " . join(" ",@_), "\n";
},
},
},
},
"quit" => {
desc => "Quit using Fileman",
maxargs => 0,
method => sub { shift->exit_requested(1); }
},
"q" => { alias => 'quit', exclude_from_completion => 1 },
};
}
This data structure describes a single command implemented by your application. "help", "exit", etc. All fields are optional. Commands are passed to Term::ShellUI using a "COMMAND SET".
If this field is a string instead of a subroutine ref, the string is printed when the command is executed (good for things like "Not implemented yet"). Examples of both subroutine and string procs can be seen in the example above.
Args can also be an arrayref. Each position in the array will be used as the corresponding argument. See "show args" in get_commands above for an example. The last argument is repeated indefinitely (see "maxargs" for how to limit this).
Finally, args can also be a string. The string is intended to be a reminder and is printed whenever the user types tab twice (i.e. "a number between 0 and 65536"). It does not affect completion at all.
If your command set includes a command named '' (the empty string), this pseudo-command will be called any time the actual command cannot be found. Here's an example:
'' => {
proc => "HA ha. No command here by that name\n",
desc => "HA ha. No help for unknown commands.",
doc => "Yet more taunting...\n",
},
Note that minargs and maxargs for the default command are ignored. method and proc will be called no matter how many arguments the user entered.
Normally, when the user types 'help', she receives a short summary of all the commands in the command set. However, if your application has 30 or more commands, this can result in information overload. To manage this, you can organize your commands into help categories
All help categories are assembled into a hash and passed to the the default help_call and "help_args" methods. If you don't want to use help categories, simply pass undef for the categories.
Here is an example of how to declare a collection of help categories:
my $helpcats = {
breakpoints => {
desc => "Commands to halt the program",
cmds => qw(break tbreak delete disable enable),
},
data => {
desc => "Commands to examine data",
cmds => ['info', 'show warranty', 'show args'],
}
};
"show warranty" and "show args" on the last line above are examples of how to include subcommands in a help category: separate the command and subcommands with whitespace.
Callbacks are functions supplied by ShellUI but intended to be called by your application. They implement common functions like 'help' and 'history'.
"help" => { desc => "Print helpful information",
args => sub { shift->help_args($helpcats, @_); },
method => sub { shift->help_call($helpcats, @_); } },
args => sub { shift->complete_files(@_) },
or
args => \&complete_files,
Starts in the current directory.
args = sub { grep { !/^\.?\.$/ } complete_onlydirs(@_) },
NUM display last N history items
(displays all history if N is omitted)
-c clear all history
-d NUM delete an item from the history
Add it to your command set using something like this:
"history" => { desc => "Prints the command history",
doc => "Specify a number to list the last N lines of history" .
"Pass -c to clear the command history, " .
"-d NUM to delete a single item\n",
args => "[-c] [-d] [number]",
method => sub { shift->history_call(@_) },
},
These are the routines that your application calls to create and use a Term::ShellUI object. Usually you simply call new() and then run() -- everything else is handled automatically. You only need to read this section if you wanted to do something out of the ordinary.
It accepts the following named parameters:
Note that this parameter does not affect in-memory history. Term::ShellUI makes no attemt to cull history so you're at the mercy of the default of whatever ReadLine library you are using. See "StifleHistory" in Term::ReadLine::Gnu for one way to change this.
Will produce the command string 'abc def'.
If you specify a code reference, then the coderef is executed and its return value is set as the prompt. Two arguments are passed to the coderef: the Term::ShellUI object, and the raw command. The raw command is always "" unless you're using command completion, where the raw command is the command line entered so far.
For example, the following line sets the prompt to "## > " where ## is the current number of history items.
$term->prompt(sub { $term->{term}->GetHistory() . " > " });
If you specify an arrayref, then the first item is the normal prompt and the second item is the prompt when the command is being continued. For instance, this would emulate Bash's behavior ($ is the normal prompt, but > is the prompt when continuing).
$term->prompt(['$', '>']);
Of course, you specify backslash_continues_command=>1 to "new" to cause commands to continue.
And, of course, you can use an array of procs too.
$term->prompt([sub {'$'}, sub {'<'}]);
NOTE: you cannot change token_chars after the constructor has been called! The regexps that use it are compiled once (m//o).
If you pass arguments, they are joined and run once. For instance, $term->run(@ARGV) allows your program to be run interactively or noninteractively:
The return value of this method is the placement of the hook routine in the hook list (1 is first) or 0 (zero) on failure.
These are routines that probably already do the right thing. If not, however, they are designed to be overridden.
By default, ShellUI simply presents another command line. Pass "blank_repeats_cmd=>1" to the constructor to get ShellUI to repeat the previous command. Override this method to supply your own behavior.
Term::ReadLine makes writing a completion routine a notoriously difficult task. Term::ShellUI goes out of its way to make it as easy as possible. The best way to write a completion routine is to start with one that already does something similar to what you want (see the "CALLBACKS" section for the completion routines that come with ShellUI).
Your routine returns an arrayref of possible completions, a string conaining a short but helpful note, or undef if an error prevented any completions from being generated. Return an empty array if there are simply no applicable competions. Be careful; the distinction between no completions and an error can be significant.
Your routine takes two arguments: a reference to the ShellUI object and cmpl, a data structure that contains all the information you need to calculate the completions. Set $term->{debug_complete}=5 to see the contents of cmpl:
NOTE: str does not respect token_chars! It is supplied unchanged from Readline and so uses whatever tokenizing it implements. Unfortunately, if you've changed token_chars, this will often be different from how Term::ShellUI would tokenize the same string.
For instance, if the cursor is on the first character of the third token, tokno will be 2 and tokoff will be 0.
If you return your completions as a list, then $twice is handled for you automatically. You could use it, for instance, to display an error message (using completemsg) telling why no completions could be found.
The following are utility routines that your completion function can call.
$self->completemsg("You cannot complete here!\n");
Note that Term::ReadLine::Perl doesn't support this so the user will always have to hit Control-L after printing. If your completion routine returns a string rather than calling completemsg() then it should work everywhere.
Your completion function needs to call this routine every time it runs if it doesn't want a space automatically appended to the completions that it returns.
force_to_string surrounds all completions with the quotes supplied by the user or, if the user didn't supply any quotes, the quote passed in default_quote. If the programmer didn't supply a default_quote and the user didn't start the token with an open quote, then force_to_string won't change anything.
Here's how to use it to force strings on two possible completions, aaa and bbb. If the user doesn't supply any quotes, the completions will be surrounded by double quotes.
args => sub { shift->force_to_string(@_,['aaa','bbb'],'"') },
Calling force_to_string escapes your completions (unless your callback calls suppress_completion_escape itself), then calls suppress_completion_escape to ensure the final quote isn't mangled.
These commands are internal to ShellUI. They are documented here only for completeness -- you should never need to call them.
my($cset, $cmd, $cname, $args) =
$self->get_deep_command($self->commands(), $tokens);
This call takes two arguments:
and it returns a list of 4 values:
You should override this routine if your application has custom completion needs (like non-trivial tokenizing, where you'll need to modify the cmpl data structure). If you override this routine, you will probably need to override call_cmd as well.
To watch and debug the completion process, you can set $self->{debug_complete} to 2 (print tokenizing), 3 (print tokenizing and results) or 4 (print everything including the cmpl data structure).
Youu should never need to call or override this function. If you do (but, trust me, you don't), set $self->{term}->Attribs->{completion_function} to point to your own routine.
See the Term::ReadLine documentation for a description of the arguments.
The history routines don't use ReadHistory and WriteHistory so they can be used even if other ReadLine libs are being used. save_history requires that the ReadLine lib supply a GetHistory call.
parms is a subset of the cmpl data structure (see the "complete(cmpl)" in complete routine for more). Briefly, it contains: cset, cmd, cname, args (see "get_deep_command"), tokens and rawline (the tokenized and untokenized command lines). See complete for full descriptions of these fields.
This call should be overridden if you have exotic command processing needs. If you override this routine, you will probably need to override the complete routine too.
Copyright (c) 2003-2011 Scott Bronson, all rights reserved. This program is free software released under the MIT license.
Scott Bronson <bronson@rinspin.com> Lester Hightower <hightowe@cpan.org> Ryan Gies <ryan@livesite.net> Martin Kluge <mk@elxsi.de>
| 2015-09-05 | perl v5.20.2 |