NAME

Term::GDBUI - A Bash/GDB-like command-line environment with autocompletion.

SYNOPSIS

use Term::GDBUI;
my $term = new Term::GDBUI(commands => get_commands());
$term->run();

get_commands() returns a command set, described below in the "COMMAND SET" section.

DESCRIPTION

This class uses the history and autocompletion features of Term::ReadLine to present a sophisticated command-line interface. It supports history, autocompletion, quoting/escaping, pretty much everything you would expect of a good shell.

To use this class, you just need to create a command set that fully describes your user interface. You need to write almost no code!

METHODS

new Term::GDBUI

Creates a new GDBUI object.

It accepts the following named parameters:

app

The name of this application as passed to Term::ReadLine::new. Defaults to $0, the name of the current executable.

blank_repeats_cmd

GDB re-executes the previous command when you enter a blank line. Bash simply presents you with another prompt. Pass 1 to get Term::GDBUI to emulate GDB's behavior or 0 to enable Bash's, the default (GDBUI's name notwithstanding).

commands

A hashref containing all the commands that GDBUI will respond to. The format of this data structure can be found below in the "COMMAND SET" section. If you do not supply any commands to the constructor, you must call the commands method to provide at least a minimal command set before using many of the following calls. You may add or delete commands or even change the entire command set at any time.

history_file

This tells whether or not we should save the command history to a file in the user's home directory. By default history_file is undef and we don't load or save the command history.

To enable history saving, supply a filename with this argument. Tilde expansion is performed, so something like "~/.myprog-history" is perfectly acceptable.

history_max

This tells how many items to save to the history file. The default is 64.

Note that this parameter does not affect in-memory history. This module makes no attemt to cull history so you're at the mercy of the default of whatever ReadLine library you are using. History may grow without bound (no big deal in this day of 1 gigabyte workstations). See i.e. Term::ReadLine::Gnu::StifleHistory() for one way to change this.

keep_quotes

If you pass keep_quotes=>1, then quote marks found surrounding the tokens will not be stripped. Normally all unescaped, unnecessary quote marks are removed.

prompt

This is the prompt that should be displayed for every request. It can be changed at any time using the prompt method. The default is "$0> " (see "app" above).

token_chars

This argument specifies the characters that should be considered tokens all by themselves. For instance, if I pass token_chars=>'=', then 'ab=123' would be parsed to ('ab', '=', '123'.) token_chars is simply a string containing all token characters.

NOTE: you cannot change token_chars after the constructor has been called! The regexps that use it are compiled once (m//o).

By default, the terminal has ornaments (text trickery to make the command line stand out) turned off. You can re-enable ornaments by calling $gdbui->{term}->ornaments(arg) where arg is described in Term::ReadLine::ornaments.

prompt

If supplied with an argument, this method sets the command-line prompt. Returns the old prompt.

commands

If supplied with an argument, it sets the current command set. This can be used to change the command set at any time. Returns the old command set.

add_commands

Adds all the commands in the supplied command set to the current command set. Replaces any commands in the current command set that have the same name.

exit_requested

If supplied with an argument, sets the finished flag to the argument (1=exit, 0=don't exit). So, to get the interpreter to exit at the end of processing the current command, call $self->exit_requested(1). Returns the old state of the flag.

blank_line

This routine is called when the user inputs a blank line. It should return a string that is the command to run or undef if nothing should happen.

By default, GDBUI simply presents another command line. Pass blank_repeats_cmd=>1 to new to get GDBUI to repeat the previous command. Override this method to supply your own behavior.

error

Called when an error occurrs. By default, the routine simply prints the msg to stderr. Override it to change this behavior.

$self->error("Oh no!  That was terrible!\n");
get_deep_command

Looks up the supplied command line in a command hash. Follows all synonyms and subcommands. Returns undef if the command could not be found.

my($cset, $cmd, $cname, $args) =
	$self->get_deep_command($self->commands(), $tokens);

This call takes two arguments:

cset

This is the command set to use. Pass $self->commands() unless you know exactly what you're doing.

tokens

This is the command line that the command should be read from. It is a reference to an array that has already been split on whitespace using parse_line.

and it returns a list of 4 values:

  1. cset: the deepest command set found. Always returned.

  2. cmd: the command hash for the command. Undef if no command was found.

  3. cname: the full name of the command. This is an array of tokens, i.e. ('show', 'info'). Returns as deep as it could find commands even if the final command was not found.

  4. args: the command's arguments (all remaining tokens after the command is found).

get_cname

This is a tiny utility function that turns the cname (array ref of names for this command as returned by get_deep_command) into a human-readable string. This function exists only to ensure that we do this consistently.

get_cset_completions

Returns a list of commands from the passed command set that are suitable for completing.

It would be nice if we could return one set of completions (without synonyms) to be displayed when the user hits tab twice, and another set (with synonyms) to actually complete on.

completemsg

your completion routine should call this to display text onscreen without messing up the command line being completed. If your completion routine prints text without calling completemsg, the cursor will no longer be displayed in the correct position.

$self->completemsg("You cannot complete here!\n");
complete

complete performs the default top-level command-line completion. Note that is not called directly by ReadLine. Rather, ReadLine calls completion_function which tokenizes the input and performs some housekeeping, then completion_function calls this one.

You should override this routine if your application has custom completion needs (like non-trivial tokenizing). If you override this routine, you will probably need to override call_cmd as well.

The one parameter, cmpl, is a data structure that contains all the information you need to calculate the completions. Set $self->{debug_complete}=5 to see the contents of cmpl. Here are the items in cmpl:

str

The exact string that needs completion. Often you don't need anything more than this.

cset

Command set for the deepest command found (see get_deep_command). If no command was found then cset is set to the topmost command set ($self->commands()).

cmd

The command hash for deepest command found or undef if no command was found (see get_deep_command). cset is the command set that contains cmd.

cname

The full name of deepest command found as an array of tokens (see get_deep_command).

args

The arguments (as a list of tokens) that should be passed to the command (see get_deep_command). Valid only if cmd is non-null. Undef if no args were passed.

argno

The index of the argument (in args) containing the cursor.

tokens

The tokenized command-line.

tokno

The index of the token containing the cursor.

tokoff

The character offset of the cursor in the token.

For instance, if the cursor is on the first character of the third token, tokno will be 2 and tokoff will be 0.

twice

True if user has hit tab twice in a row. This usually means that you should print a message explaining the possible completions.

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.

rawline

The command line as a string, exactly as entered by the user.

rawstart

The character position of the cursor in rawline.

completion_function

This is the entrypoint to the ReadLine completion callback. It sets up a bunch of data, then calls complete to calculate the actual completion.

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.

get_cmd_summary

Prints a one-line summary for the given command.

get_cmd_help

Prints the full help text for the given command.

get_category_summary

Prints a one-line summary for the catgetory named $name in the category hash $cat.

get_category_help

Returns a string containing the full help for the catgetory named $name and passed in $cat. The full help is a list of one-line summaries of the commands in this category.

get_all_cmd_summaries

Pass it a command set, and it will return a string containing the summaries for each command in the set.

load_history

If $self->{history_file} is set (see new), this will load all history from that file. Called by run on startup. If you don't use run, you will need to call this command manually.

save_history

If $self->{history_file} is set (see new), this will save all history to that file. Called by run on shutdown. If you don't use run, you will need to call this command manually.

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_cmd

Executes a command and returns the result. It takes a single argument: the parms data structure.

parms is a subset of the cmpl data structure (see the 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.

process_a_cmd

Prompts for and returns the results from a single command. Returns undef if no command was called.

run

The main loop. Processes all commands until someone calls exit_requested(true).

CALLBACKS

These functions are meant to be called by the commands themselves (usually via the 'meth' field). They offer some assistance in implementing common functions like 'help'.

help_call

Help commands can call this routine to print information about command sets.

cats

A hash of available help categories (see CATEGORIES below for more). Pass undef if you don't have any help categories.

topic

The item upon which help should be printed (the arguments to the help command.

Here is the most common way to implement a help command:

"help" =>   { desc => "Print helpful information",
              args => sub { shift->help_args($helpcats, @_); },
              meth => sub { shift->help_call($helpcats, @_); } },

This follows synonyms and subcommands, completing the entire way. It works exactly as you'd expect.

help_args

This provides argument completion for help commands. Call this as shown in the example in help_call.

complete_files

Allows any command to easily complete on objects from the filesystem. Call it using either "args => sub { shift->complete_files(@_)" or "args => \&complete_files". See the "ls" example in the "COMMAND SET" section below.

complete_onlyfiles

Like complete_files, but excludes directories, device nodes, etc. It returns regular files only.

complete_onlydirs

Like complete_files, but excludes files, device nodes, etc. It returns only directories. It does return the . and .. special directories so you'll need to remove those manually if you don't want to see them.

TOKEN PARSING

Term::GDBUI used to use the Text::ParseWords module to tokenize the command line. However, requirements have gotten significantly more complex since then, forcing this module to do all tokenizing itself.

parsebail

If the parsel routine or any of its subroutines runs into a fatal error, they call parsebail to present a very descriptive diagnostic.

parsel

This is the heinous routine that actually does the parsing. You should never need to call it directly. Call parse_line instead.

parse_line($line, $cursorpos)

This is the entrypoint to this module's parsing functionality. It converts a line into tokens, respecting quoted text, escaped characters, etc. It also keeps track of a cursor position on the input text, returning the token number and offset within the token where that position can be found in the output.

This routine originally bore some resemblance to Text::ParseWords. It has changed almost completely, however, to support keeping track of the cursor position. It also has nicer failure modes, modular quoting, token characters (see token_chars in new), etc. This routine now does much more.

Arguments:

line

This is a string containing the command-line to parse.

This routine also accepts the following named parameters:

cursorpos

This is the character position in the line to keep track of. Pass undef (by not specifying it) or the empty string to have the line processed with cursorpos ignored.

Note that passing undef is not the same as passing some random number and ignoring the result! For instance, if you pass 0 and the line begins with whitespace, you'll get a 0-length token at the beginning of the line to represent the cursor in the middle of the whitespace. This allows command completion to work even when the cursor is not near any tokens. If you pass undef, all whitespace at the beginning and end of the line will be trimmed as you would expect.

If it is ambiguous whether the cursor should belong to the previous token or to the following one (i.e. if it's between two quoted strings, say "a""b" or a token_char), it always gravitates to the previous token. This makes more sense when completing.

fixclosequote

Sometimes you want to try to recover from a missing close quote (for instance, when calculating completions), but usually you want a missing close quote to be a fatal error. fixclosequote=>1 will implicitly insert the correct quote if it's missing. fixclosequote=>0 is the default.

messages

parse_line is capable of printing very informative error messages. However, sometimes you don't care enough to print a message (like when calculating completions). Messages are printed by default, so pass messages=>0 to turn them off.

This function returns a reference to an array containing three items:

tokens

A the tokens that the line was separated into (ref to an array of strings).

tokno

The number of the token (index into the previous array) that contains cursorpos.

tokoff

The character offet into tokno of cursorpos.

If the cursor is at the end of the token, tokoff will point to 1 character past the last character in tokno, a non-existant character. If the cursor is between tokens (surrounded by whitespace), a zero-length token will be created for it.

parse_escape

Escapes characters that would be otherwise interpreted by the parser. Will accept either a single string or an arrayref of strings (which will be modified in-place).

join_line

This routine does a somewhat intelligent job of joining tokens back into a command line. If token_chars (see new) is empty (the default), then it just escapes backslashes and quotes, and joins the tokens with spaces.

However, if token_chars is nonempty, it tries to insert a visually pleasing amount of space between the tokens. For instance, rather than 'a ( b , c )', it tries to produce 'a (b, c)'. It won't reformat any tokens that aren't found in $self->{token_chars}, of course.

To change the formatting, you can redefine the variables $self->{space_none}, $self->{space_before}, and $self->{space_after}. Each variable is a string containing all characters that should not be surrounded by whitespace, should have whitespace before, and should have whitespace after, respectively. Any character found in token_chars, but non in any of these space_ variables, will have space placed both before and after.

COMMAND SET

A command set describes your application's entire user interface. It's probably easiest to explain this with a working example. Combine the following get_commands() routine with the code shown in the SYNOPSIS above, and you'll have a real-life shellish thingy that supports the following commands:

h

This is just a synonym for "help". It is not listed in the possible completions because it just clutters up the list without being useful.

help

The default implementation for the help command

ls

This command shows how to perform completion using the complete_files routine, how a proc can process its arguments, and how to provide more comprehensive help.

show

This is an example showing how the GDB show command can be implemented. Both "show warranty" and "show args" are valid subcommands.

show args

This is a hypothetical command. It uses a static completion for the first argument (either "create" or "delete") and the standard file completion for the second. When executed, it echoes its own command name followed by its arguments.

quit

How to nicely quit. Even if no quit command is supplied, Term::GDBUI follows Term::ReadLine's default of quitting when Control-D is pressed.

This code is rather large because it is intended to be reasonably comprehensive and demonstrate most of the features supported by Term::GDBUI's command set. For a more reasonable example, see the "fileman-example" file that ships with this module.

 sub get_commands
 {
     return {
         "h" =>      { syn => "help", exclude_from_completion=>1},
         "help" => {
             desc => "Print helpful information",
             args => sub { shift->help_args(undef, @_); },
             meth => sub { shift->help_call(undef, @_); }
         },
         "ls" => {
             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); }
		 },
     };
 }

COMMAND HASH

A command is described by a relatively small number of fields: desc, args, proc, meth, etc. These fields are collected into a data structure called a command hash. A command set is simply a collection of command hashes.

The following fields may be found in a command hash:

desc

A short, one-line description for the command. Normally this is a simple string.

If you store a reference to a subroutine in this field, the routine will be called to calculate the description to print. Your subroutine should accept two arguments, $self (the Term::GDBUI object), and $cmd (the command hash for the command), and return a string containing the command's description.

doc

A comprehensive, many-line description for the command. Normally this is stored as a simple string.

If you store a reference to a subroutine in this field, the routine will be called to calculate the documentation. Your subroutine should accept two arguments: self (the Term::GDBUI object), and cmd (the command hash for the command), and return a string containing the command's documentation.

maxargs
minargs

These set the maximum and minimum number of arguments that this command will accept. By default, the command can accept any number of arguments.

proc

This contains a reference to the subroutine that should be called when this command should be executed. Arguments are those passed on the command line, return value is returned by call_cmd and process_a_cmd (i.e. it is usually ignored).

If this field is a string instead of a subroutine ref, the string (i.e. "Not implemented yet") is printed when the command is executed. Examples of both subroutine and string procs can be seen in the example above.

proc is similar to meth, but only passes the command's arguments.

meth

Like proc, but includes more arguments. Where proc simply passes the arguments for the command, meth also passes the Term::GDBUI object and the command's parms object (see call_cmd for more on parms).

Like proc, meth may also be a string. If a command has both a meth and a proc, the meth takes precedence.

args

This tells how to complete the command's arguments. It is usually a subroutine. See complete_files) for an reasonably simple example, and the complete routine for a description of the arguments and cmpl data structure.

Args can also be an arrayref. Each position in the array will be used as the corresponding argument. For instance, if a command takes two arguments, an operation and a file

Finally, args can also be a string that is a reminder and is printed whenever the user types tab twice.

cmds

Command sets can be recursive. This allows a command to implement subcommands (like GDB's info and show). The cmds field specifies the command set that this command implements.

A command with subcommands should only have two fields: cmds (of course), and desc to briefly describe this collection of subcommands. It may also implement doc, but GDBUI's default behavior of printing a summary of subcommands for the command is usually sufficient. Any other fields (args, meth, maxargs, etc) will be ignored.

exclude_from_completion

If this field exists, then the command will be excluded from command-line completion. This is useful for one-letter command synonyms, such as "h"->"help". To include "h" in the completions is usually mildly confusing, especially when there are a lot of other single-letter synonyms. This is usable in all commands, not just synonyms.

CATEGORIES

Normally, when the user types 'help', she receives a summary of every supported command. 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.

Here is an example of how to declare a collection of help categories:

  my $helpcats = {
	  breakpoints => {
		  desc => "Commands to force the program to stop at certain points",
		  cmds => qw(break tbreak delete disable enable),
	  },
	  data => {
		  desc => "Commands to examine data",
		  cmds => ['info', 'show warranty', 'show args'],
	  }
  };

"show warranty" and "show args" are examples of how to include subcommands in a help category.

BUGS

The Parsing/Tokeniznig should be split off into another module, perhaps soemthing like Text::ParseWords::Cursor.

It would be nice if this module understood some sort of extended EBNF so it could automatically tokenize and complete commands for very complex input syntaxes. Of course, that would be one hell of a big project...

LICENSE

Copyright (c) 2003 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.

AUTHOR

Scott Bronson <bronson@rinspin.com>