Term::GDBUI - A fully-featured shell-like command line environment |
Term::GDBUI - A fully-featured shell-like command line environment
use Term::GDBUI; my $term = new Term::GDBUI(commands => get_commands()); # (see below for the code to get_commands) $term->run();
Term::GDBUI uses the history and autocompletion features of the Term::ReadLine manpage to present a sophisticated command-line interface to the user. It tries to make every feature you would expect to see in a fully interactive shell trivial to implement. You simply declare your command set and let GDBUI take care of the heavy lifting.
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 COMMANDs:
This code is fairly comprehensive because it attempts to demonstrate most of Term::GDBUI'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, @_); }, meth => sub { shift->help_call(undef, @_); } }, "h" => { syn => "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::GDBUI::complete_files ], desc => "Demonstrate method calling", meth => sub { my $self = shift; my $parms = shift; print $self->get_cname($parms->{cname}) . ": " . join(" ",@_), "\n"; }, }, }, }, "quit" => { desc => "Quit using Fileman", maxargs => 0, meth => sub { shift->exit_requested(1); } }, }; }
This data structure describes a single command implemented by your application. ``help'', ``exit'', etc. All fields are optional. Commands are passed to Term::GDBUI 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. meth 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 GDBUI 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, @_); }, meth => sub { shift->help_call($helpcats, @_); } },
args => sub { shift->complete_files(@_) },
or
args => \&complete_files,
Starts in the current directory.
args = sub { grep { !/^\.?\.$/ } complete_onlydirs(@_) },
Here's an example of how you would add history completion to your command set:
my $cset = { "" => { args => sub { shift->complete_history(@_) } }, # ... more commands go here };
To watch this in action, run your app, type a bang and then a tab (``!<tab>'').
There is one catch: if you start using completion, be sure to enter the ENTIRE command. If you enter a partial command, Readline will unfortunately stop looking for the match after just the first word (usually the command name). This means that if you want to run ``!abc def ghi'', Readline will execute the first command that begins with ``abc'', even though you may have specified another command. Entering the entire command works around this limitation. (If Readline properly supported $term->Attribs->{history_word_delimiters}='\n', this limitation would go away).
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]", meth => sub { shift->history_call(@_) }, },
These are the routines that your application calls to create
and use a Term::GDBUI 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.
named args...
)It accepts the following named parameters:
new Term::ReadLine $args{'app'}
). However, if
you can create a new Term::ReadLine object yourself and
supply it using the term argument.
~/.myprog-history
is perfectly acceptable.
Note that this parameter does not affect in-memory history. Term::GDBUI 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 the Term::ReadLine::Gnu manpage for one way to change this.
disable_history_expansion=>1
.
keep_quotes=>1
, however, they are preserved.
This is useful if your application uses quotes to delimit, say,
Perl-style strings.
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::GDBUI 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 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). Also, until the Gnu Readline library can accept ``=[],'' without diving into an endless loop, we will not tell history expansion to use token_chars (it uses `` \t\n()<>;&|'' by default).
process_a_cmd()
run()
/"exit_requested(exitflag)"|exit_requested(true)
.
prompt(newprompt)
commands(newcmds)
add_commands(newcmds)
exit_requested(exitflag)
$self->exit_requested(1)
. To cancel an exit
request before the command is finished, $self->exit_requested(0)
.
Returns the old state of the flag.
get_cname(cname)
These are routines that probably already do the right thing. If not, however, they are designed to be overridden.
blank_line()
By default, GDBUI simply presents another command line. Pass
blank_repeats_cmd=>1
to the constructor to get GDBUI to repeat the previous
command. Override this method to supply your own behavior.
error(msg)
Term::ReadLine makes writing a completion routine a notoriously difficult task. Term::GDBUI 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 GDBUI).
Your routine returns either an arrayref of possible completions 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 GDBUI 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::GDBUI 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.
completemsg(msg)
$self->completemsg("You cannot complete here!\n");
suppress_completion_append_character()
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.
suppress_completion_escape()
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 GDBUI. 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:
commands()
unless you know exactly what you're doing.
and it returns a list of 4 values:
get_cset_completions(cset)
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 the Term::ReadLine manpage documentation for a description of the arguments.
commands()
if cset is not specified.
commands()
if cset is not specified.
get_all_cmd_summaries(cset)
load_history()
save_history()
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.
call_command(parms)
parms is a subset of the cmpl data structure (see the complete/complete(cmpl) 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.
History expansion does not respect token_chars. To make it do so would require either adding this feature to the readline library or re-writing history_expand in Perl -- neither of which sounds very realistic.
Copyright (c) 2003-2006 Scott Bronson, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Scott Bronson <bronson@rinspin.com>
Term::GDBUI - A fully-featured shell-like command line environment |