package CommandTerm
::Curses
;
'dataFace' => 0, # normal
'statusFace' => 2, # green
my ($class, $name, $cfgfile, $app_config) = @_;
$self->InitSignalHandlers;
$self->Init($name, $cfgfile, $app_config, \
%DerivedConfig);
$self->{'ReadCallbacks'} = {};
$self->{'WriteCallbacks'} = {};
$self->{'GotInterrupt'} = 0;
# $self->{'Pty'} = undef;
$self->{'ScrollWin'} = $win->subwin($LINES-1, $COLS, 0, 0);
$self->{'PromptWin'} = $win->subwin(1, $PROMPT_LENGTH+1, $LINES-1, 0);
$self->{'EntryWin'} = $win->subwin(1, $LINES-$PROMPT_LENGTH, $LINES-1, $PROMPT_LENGTH);
my ($fileno, $fd_read, $fd_write);
init_pair
(1, COLOR_RED
, COLOR_BLACK
);
init_pair
(2, COLOR_GREEN
, COLOR_BLACK
);
init_pair
(3, COLOR_YELLOW
, COLOR_BLACK
);
init_pair
(4, COLOR_BLUE
, COLOR_BLACK
);
init_pair
(5, COLOR_MAGENTA
, COLOR_BLACK
);
init_pair
(6, COLOR_CYAN
, COLOR_BLACK
);
init_pair
(7, COLOR_WHITE
, COLOR_BLACK
);
$self->PromptWin->attron(A_BOLD
);
$self->ScrollWin->scrollok(1);
'readable' => sub{ $self->ReadLine->callback_read_char; },
$self->ReadLine->CallbackHandlerInstall(
sub { $self->ProcessLine(@_); }
if( $self->GotInterrupt ) {
next if select($fd_read = $self->ReadFD, $fd_write = $self->WriteFD, undef, 1.0) < 0;
foreach $fileno (keys %{ $self->ReadCallbacks }) {
&{ $self->{'ReadCallbacks'}{$fileno} } if vec($fd_read, $fileno, 1);
foreach $fileno (keys %{ $self->WriteCallbacks }) {
&{ $self->{'WriteCallbacks'}{$fileno} } if vec($fd_write, $fileno, 1);
my ($self, $fh, $readwrite, $func) = @_;
return unless defined($fh) and defined($readwrite);
my $fileno = fileno($fh);
if( $readwrite eq 'readable' ) {
if( defined($func) and ref($func) eq 'CODE' ) {
vec($self->{'ReadFD'}, $fileno, 1) = 1;
$self->{'ReadCallbacks'}{$fileno} = $func;
vec($self->{'ReadFD'}, $fileno, 1) = 0;
delete $self->{'ReadCallbacks'}{$fileno}
} elsif( $readwrite eq 'writable' ) {
if( defined($func) and ref($func) eq 'CODE' ) {
vec($self->{'WriteFD'}, $fileno, 1) = 1;
$self->{'WriteCallbacks'}{$fileno} = $func;
vec($self->{'WriteFD'}, $fileno, 1) = 0;
delete $self->{'WriteCallbacks'}{$fileno};
$self->PrintError("Bad mode to fileevent: '$readwrite'\n");
my ($opt_h, $opt_r, $opt_n);
$self->get_options(\
@args, ['no_pass_through'], 'h' => \
$opt_h, 'r' => \
$opt_r) or return;
if( $opt_n and $opt_n !~ /^\d+$/ ) {
$self->PrintError("Argument to history '$opt_n' isn't numeric.\n");
my @history = $self->ReadLine->GetHistory;
for(my $i=$#history; $i>=0; $i--) {
$str .= ($opt_h ?
'' : "\t$i\t" . "$history[$i]\n");
last if $opt_n and ($#history - $i + 1) >= $opt_n;
$opt_n = $#history unless defined($opt_n);
for(my $i=$#history-$opt_n+1; $i<=$#history; $i++) {
$str .= ($opt_h ?
'' : "\t$i\t" . "$history[$i]\n");
$self->PrintStatus($str);
# $self->Pty(new IO::Pty);
# my $tty = $self->Pty->slave;
# my $termios = POSIX::Termios->new;
# $termios->getattr($tty->fileno) or die;
# $termios->setiflag(IGNCR);
# for(my $i=0; $i<NCCS; $i++) {
# $termios->setcc($i, _POSIX_VDISABLE);
# $termios->setcc(VMIN, 1);
# $termios->setcc(VTIME, 0);
# $termios->setattr($tty->fileno, TCSANOW) or die;
# open(STDERR, ">&" . $tty->fileno) or die "Couldn't re-open STDERR: $!";
# $self->fileevent($self->Pty, 'readable' => sub { $self->CaptureOutput });
# unless( POSIX::read($Pty->fileno, $data, 1024) ) {
# $self->fileevent($Pty, 'readable' => '');
# $self->PrintError("Bad sysread from Pty: $!\n");
# $self->PrintError("Closing Pty and restoring STDOUT.\n");
# $self->PrintData($data);
my ($self, $cmd, @args) = @_;
$dir = $self->GlobExpand($dir);
return unless defined($dir);
$self->PrintData( getcwd
);
$self->PrintError("Couldn't cd to '$dir': $!\n");
if( $self->Which($cmd) ) {
# my $ttyname = $self->Pty->IO::Pty::ttyname;
# system("$cmd @args 2>&1 > $ttyname");
# $self->PrintStatus( "ttyname: ", $self->Pty->IO::Pty::ttyname, "\n" );
# $self->PrintStatus( `$cmd @args` );
$self->PrintError("Command not found: '$cmd'\n");
my $entry_win = $self->EntryWin;
$entry_win->addstr(0, 0, $self->Attribs->{'line_buffer'});
$entry_win->move(0, $self->Attribs->{'point'});
my $ReadLine = $self->ReadLine;
my $Attribs = $self->Attribs;
unless( defined($line) ) {
$Attribs->{'point'} = $Attribs->{'end'} = 0;
$self->PrintStatus("> $line\n");
$self->SUPER::ProcessLine
($line);
# Since we're not using ReadLine interactively, set the history position
# to the end every time through.
$ReadLine->history_set_pos( scalar($ReadLine->GetHistory) );
$self->PromptWin->addstr(0, 0, $self->GetPrompt);
$self->PromptWin->noutrefresh;
$self->SUPER::InitSignalHandlers
;
$SIG{'INT'} = sub { $self->GotInterrupt(1); };
$self->SUPER::InitReadLine
;
my $NULLOUT = FileHandle
->new('> /dev/null') or
die "Couldn't open '/dev/null': $!\n";
$self->Attribs->{'outstream'} = $NULLOUT;
$self->Attribs->{'redisplay_function'} = sub { $self->UpdateEntry(@_); };
#We don't want any dinging at all, it's alarming. :-)
$self->ReadLine->parse_and_bind('set bell-style none');
&{ $self->TogglePromptCallback };
my $ReadLine = $self->ReadLine;
my $Attribs = $self->Attribs;
if( $Attribs and $Attribs->{'end'} != 0 ) {
$Attribs->{'point'} = $Attribs->{'end'} = 0;
&{ $self->HandleInterruptCallback };
my ($self, $matchlist_ref, $num_matches, $longest, $striplen) = @_;
for(my $i=1; $i<=$num_matches; $i++) {
$match = $matchlist_ref->[$i];
push @matches, substr $match, $striplen;
my $num_cols = int($COLS/($longest+1)) || 1;
my $skip = int($num_matches/$num_cols);
$skip++ if ($num_matches/$num_cols) != $skip;
for($i=0; $i<$skip; $i++) {
for($j=0; $j<$num_cols; $j++) {
$index = $i + ($j * $skip);
if( $index < $num_matches ) {
$str .= sprintf("%-${longest}s ", $matches[$index]);
$self->PrintStatus(">\n");
# $self->fileevent($self->Pty, 'readable' => '');
my ($self, $how, @what) = @_;
my $LogFH = $self->LogFH;
my $scroll_win = $self->ScrollWin;
my $ReDirFH = $self->ReDirFH;
my $what = join '', @what;
print $LogFH $what if defined $LogFH;
return if $self->InExecFile and $how ne $self->ErrorFace;
$scroll_win->attron(COLOR_PAIR
($how));
my @lines = split(/\n/, $what);
if( $self->Scroll > $LINES-2 ) {
$scroll_win->addstr($LINES-2, 0, shift(@lines));
$scroll_win->addstr($self->{'Scroll'}++, 0, shift(@lines));
$scroll_win->attroff(COLOR_PAIR
($how));
$scroll_win->noutrefresh;
sub DefaultInterruptCallback
{
$self->PrintStatus(">\n");
# sub CommandTerm::Curses::clear {
# $self->ScrollWin->clear;
# $self->ScrollWin->refresh;